MyBatis 缓存之Redis简单实现 您所在的位置:网站首页 mybatis redis缓存 MyBatis 缓存之Redis简单实现

MyBatis 缓存之Redis简单实现

2023-10-09 09:13| 来源: 网络整理| 查看: 265

前言

MyBatis 提供的缓存机制都是基于Cache 接口而实现,因此我们也可以通过实现该接口创建自定义的缓存实现。

Redis 的缓存实现

简单来说,在MyBatis开启二级缓存的前提下,通过使用自定义的缓存实现类,使用Redis完成对缓存信息的查询和更新。

先来看一下 maven 依赖,本文使用的是Spring boot框架,依赖信息相对简单清晰。

org.springframework.boot spring-boot-starter-data-redis org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.2

再来看一下具体的实现类,

public class RedisCache implements Cache { private static final Logger logger = LoggerFactory.getLogger(RedisCache.class); private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private final String id; private RedisTemplate redisTemplate; private static final long EXPIRE_TIME_IN_MINUTES = 30; public RedisCache(String id){ if(id == null) throw new IllegalArgumentException("Cache instance requires an ID"); this.id = id; } @Override public String getId() { return this.id; } private RedisTemplate getRedisTemplate() { if(null == this.redisTemplate){ logger.debug("set redisTemplate"); this.redisTemplate = ApplicationContextHolder.getBean("redisTemplate"); } return this.redisTemplate; } public void setRedisTemplate(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } @Override public void putObject(Object key, Object value) { ValueOperations opsForValue = this.getRedisTemplate().opsForValue(); opsForValue.set(key, value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES); logger.debug("Put query result to redis"); } @Override public Object getObject(Object key) { ValueOperations opsForValue = this.getRedisTemplate().opsForValue(); logger.debug("Get cached query result from redis"); return opsForValue.get(key); } @Override public Object removeObject(Object key) { this.getRedisTemplate().delete(key); logger.debug("Remove cached query result from redis"); return key; } @Override public void clear() { this.getRedisTemplate().execute(new RedisCallback() { @Override public Object doInRedis(RedisConnection redisConnection) throws DataAccessException { logger.debug("flush redis"); redisConnection.flushDb(); return null; } }); } @Override public int getSize() { return 0; } @Override public ReadWriteLock getReadWriteLock() { return this.readWriteLock; } }

这里我们采用了 RedisTemplate 实现对缓存的操作,而不是采用 jedis,原因在于Jedis是Redis官方推荐的面向Java的操作Redis的客户端,而RedisTemplate是SpringDataRedis中对JedisApi的高度封装。SpringDataRedis相对于Jedis来说可以方便地更换Redis的Java客户端,比Jedis多了自动管理连接池的特性,方便与其他Spring框架进行搭配使用。

需要注意的是,此处的 redisTemplate 属性不同通过 autowired 方式获得,原因在于 RedisCache 本身就不是一个bean,因此我们考虑使用一个辅助类实线bean的获取。

public class ApplicationContextHolder implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext; } public static ApplicationContext getApplicationContext(){ return context; } public static T getBean(Class clazz){ return context.getBean(clazz); } public static T getBean(String name){ return (T)context.getBean(name); } }

最后还需要针对缓存做一些配置

mapper 文件内容相对简单,主要是基于主键信息的增删查改操作,此处不再赘述。

测试

当我们使用浏览器发送下述请求时,能获得如下的相应信息, 这里写图片描述

而此时,Redis 数据库中存在如下的 key-value 信息, 这里写图片描述

当我们再次发送上述请求能够获得同样的响应信息,观察如下日志信息,

第一次请求的日志信息 这里写图片描述

第二次请求的日志信息 这里写图片描述

可以看出,每次查询的时候先查询缓存中是否存在相关信息,如果存在直接返回,如果不存在,则去访问数据库,并将结果信息写入缓存以供下次查询。

同样,我们可以借助 RESTClient 工具发送 post 请求,实现对数据库信息的修改, 这里写图片描述

而此时,Redis 数据库中的信息已被刷新, 这里写图片描述

这也说明了二级缓存的刷新时机,即事务的提交会刷新该namespace下的二级缓存。

总结

本文描述了一种基于 RedisTemplate 的分布式缓存的简单实现方式,当然还有很多不足之处,比如缓存数据库崩溃等异常情况未考虑,希望能对读者在创建分布式缓存时提供一种思路。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有